﻿using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using Magicodes.ExporterAndImporter.Excel;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NP.BPMReportPlatform.AnalysisInstance.Dtos;
using NP.BPMReportPlatform.BPMPlatform;
using NP.BPMReportPlatform.DBHelper;
using NP.BPMReportPlatform.Entities.BPM_Business;
using NP.BPMReportPlatform.Entities.BPM_Business.Common;
using NP.BPMReportPlatform.Entities.BPM_Engine;
using NP.BPMReportPlatform.Entities.BPM_Platform;
using NP.BPMReportPlatform.Reports.ZPSPXT.Dtos;
using NP.BPMReportPlatform.Utilities;
using NP.BPMReportPlatform.Utils;
using NPOI.SS.UserModel;
using Serilog;
using SqlSugar;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Users;
using static ICSharpCode.SharpZipLib.Zip.ExtendedUnixData;
using Users = NP.BPMReportPlatform.Entities.BPM_Platform.Users;

namespace NP.BPMReportPlatform.Reports.ZPSPXT
{
    public class ZPSPXTService: BPMReportPlatformAppService, IZPSPXTService
    {
        private readonly SqlSugarClient _db;
        private readonly SqlSugarClient _dbPlatform;
        private readonly IBPMUtilsAppService _bPMUtilsApp;
        private readonly IBPMPlatformAppService _iBPMPlatformApp;
        private readonly SqlSugarClient _dbEngine;
        private readonly ILogger _logger;
        private readonly IExcelImporter _importer;
        private readonly IConfiguration _configuration;
        public ZPSPXTService(ISqlSugarAppService sqlSugarAppService, IBPMUtilsAppService bPMUtilsApp
            , IBPMPlatformAppService iBPMPlatformApp, ILogger logger, IExcelImporter importer
            , IConfiguration configuration)
        {
            _db = sqlSugarAppService.GetBusinessInstance();
            _dbPlatform = sqlSugarAppService.GetPlatformInstance();
            _dbEngine = sqlSugarAppService.GetEngineInstance();
            _bPMUtilsApp = bPMUtilsApp;
            _iBPMPlatformApp = iBPMPlatformApp;
            _logger = logger;
            _importer = importer;
            _configuration = configuration;
        }

        public async Task<PagedResultDto<ZPSPXTDto>> GetAllAsync(ZPSPXTInput input)
        {
            var currentUserId = Guid.Empty;
            if (!input.IsQueryAll)
            {
                var currentUserDto = _dbPlatform.Queryable<Users>().Where(x => x.WorkNumber.Equals(CurrentUser.UserName)).First();
                if (currentUserDto != null)
                {
                    currentUserId = currentUserDto.UserId;
                }
            }

            RefAsync<int> totalCount = 0;

            var listQueryable = _db.Queryable<CommonApprovalProcess, BusinessProcessesNew>(
                (x, b) => x.InstanceNumber == b.InstanceId).Where((x, b) => x.BTID == "ZPSPXT" && b.BTID == "ZPSPXT")
                .WhereIF(!input.IsQueryAll, (x, b) => x.AddUserId.Equals(currentUserId))
                .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), (x, b) => x.InstanceNumber == input.InstanceNumber)
                .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), (x, b) => x.AddUserName.Contains(input.AddUserName))
                .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null,
                    (x, b) => x.AddTime >= input.StartCreationTime && x.AddTime <= input.EndCreationTime)
                .WhereIF(!string.IsNullOrWhiteSpace(input.Org), (x, b) => x.Text2.Contains(input.Org) || x.Text3.Contains(input.Org)
                 || x.Text4.Contains(input.Org) || x.Text5.Contains(input.Org) || x.Text16.Contains(input.Org) || x.Text18.Contains(input.Org))
                .Select((x, b) => new ZPSPXTDto
                {
                    InstanceNumber = x.InstanceNumber,
                    ProcessStartTime = x.AddTime,
                    ProcessStartTimeStr = x.AddTime != null ? x.AddTime.Value.ToString(DateFormatHelper.DateTimeFormat) : "",
                    ProcessStartUserName = x.AddUserName,
                    OrderStatus = b.ProcessStatusName,
                    OrgName2 = x.Text2,// 选择部门名称
                    OrgName3 = x.Text3,// 组织单元3
                    OrgName4 = x.Text4,// 组织单元4
                    OrgName5 = x.Text5,// 组织单元5
                    OfficerDesc = x.Text6,// 目录1 离职补员/新增招聘
                    //= x.Text7,// 目录2 正式员工/劳务工
                    //= x.Text8,// 目录3 编制内/编制外
                    //= x.Text9,// HC编制数
                    PostName = x.Text10,// 岗位名称
                    PostLevel = x.Text11,// 岗位职级
                    OrgName6 = x.Text16,// 组织单元6
                    OrgName7 = x.Text18,// 组织单元7
                    DemandDesc = x.TextArea1,// 需求描述
                    Suggestions = x.TextArea2,// 人事建议
                    OverTime = b.FinishTime,
                    OverTimeStr = b.FinishTime != null && b.FinishTime != DateTime.MinValue ? b.FinishTime.Value.ToString(DateFormatHelper.DateTimeFormat) : ""
                });

            var listViewDto = await listQueryable.MergeTable().OrderBy(x => x.ProcessStartTime, OrderByType.Desc).ToPageListAsync(input.PageIndex, input.PageSize, totalCount);

            var instanceNumbers = listViewDto.Select(x => x.InstanceNumber).ToList();

            var userId = await _iBPMPlatformApp.GetUserAsync(CurrentUser.UserName);

            var ccUsers = await _db.Queryable<InstanceCCUsers>().Where(x => instanceNumbers.Contains(x.InstanceNumber) && x.CCType == 1).ToListAsync();

            var instanceDataQuery = _dbEngine.Queryable<Instances, Activities, Tasks>(
                (a, c, d) => new JoinQueryInfos(JoinType.Inner, a.InstanceId == c.InstanceId,
                JoinType.Left, c.ActivityId.ToString() == d.ActivityId))
                .Where((a, c, d) => a.BTID == "ZPSPXT" && instanceNumbers.Contains(a.Number))
                .Select((a, c, d) => new AnalysisInstanceResultDto
                {
                    InstanceId = a.InstanceId,
                    InstanceNumber = a.Number,
                    InstanceTopic = a.Topic,
                    ProcessName = a.ProcessName,

                    Name = c.Name,
                    UserName = d.UserName,
                    GrandNodeId = c.GrandNodeId,
                    Order = c.Order,
                    ActivityId = c.ActivityId,
                });

            var instanceData = await instanceDataQuery.ToListAsync();
            var instanceGroupData = instanceData.GroupBy(x => x.InstanceNumber).ToDictionary(x => x.Key, x => x);

            listViewDto.ForEach(x =>
            {
                x.Url = _bPMUtilsApp.GetProcessUrl(x.InstanceNumber, userId);

                x.CCUserName = ccUsers.Where(q => q.InstanceNumber == x.InstanceNumber).Select(q => q.UserName).Distinct().JoinAsString(",");

                var groupData = instanceGroupData.Where(q => q.Key == x.InstanceNumber).SelectMany(q => q.Value).ToList();

                var activities = groupData.OrderBy(x => x.Order).ToList()
                   .GroupBy(b => new { b.InstanceId, b.Name, b.GrandNodeId })
                   .ToDictionary(k => k.Key, v => v.ToList());

                var index = 0;
                foreach (var activity in activities)
                {
                    index++;
                    if (activity.Key.Name == "开始")
                    {
                        continue;
                    }
                    if (index == 2)
                    {
                        x.FirstApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 3)
                    {
                        x.SecondApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 4)
                    {
                        x.ThirdApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 5)
                    {
                        x.FouthApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 6)
                    {
                        x.FifthApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                }
            });

            //返回结果
            return new PagedResultDto<ZPSPXTDto>()
            {
                TotalCount = totalCount,
                Items = listViewDto
            };
        }

        public async Task<List<ZPSPXTDto>> ExportAsync(ZPSPXTInput input)
        {
            var currentUserId = Guid.Empty;
            if (!input.IsQueryAll)
            {
                var currentUserDto = _dbPlatform.Queryable<Users>().Where(x => x.WorkNumber.Equals(CurrentUser.UserName)).First();
                if (currentUserDto != null)
                {
                    currentUserId = currentUserDto.UserId;
                }
            }

            var listQueryable = _db.Queryable<CommonApprovalProcess, BusinessProcessesNew, InstanceCCUsers>(
                (x, b, c) => new JoinQueryInfos(JoinType.Inner, x.InstanceNumber == b.InstanceId,
                JoinType.Left, x.InstanceNumber == c.InstanceNumber && c.CCType == 1))
                .InnerJoin<Instances>((x, b, c, i) => x.InstanceNumber == i.Number).AS<Instances>("BPM_Engine.Instances")
                .InnerJoin<Activities>((x, b, c, i, a) => i.InstanceId == a.InstanceId).AS<Activities>("BPM_Engine.Activities")
                .InnerJoin<Tasks>((x, b, c, i, a, t) => a.ActivityId.ToString() == t.ActivityId).AS<Tasks>("BPM_Engine.Tasks")
                .Where((x, b, c, i, a, t) => x.BTID == "ZPSPXT" && b.BTID == "ZPSPXT")
                .WhereIF(!input.IsQueryAll, (x, b, c, i, a, t) => x.AddUserId.Equals(currentUserId))
                .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), (x, b, c, i, a, t) => x.InstanceNumber == input.InstanceNumber)
                .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), (x, b, c, i, a, t) => x.AddUserName.Contains(input.AddUserName))
                .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null,
                    (x, b, c, i, a, t) => x.AddTime >= input.StartCreationTime && x.AddTime <= input.EndCreationTime)
                .WhereIF(!string.IsNullOrWhiteSpace(input.Org), (x, b, c, i, a, t) => x.Text2.Contains(input.Org) || x.Text3.Contains(input.Org)
                 || x.Text4.Contains(input.Org) || x.Text5.Contains(input.Org) || x.Text16.Contains(input.Org) || x.Text18.Contains(input.Org))
                .Select((x, b, c, i, a, t) => new ZPSPXTDto
                {
                    InstanceNumber = x.InstanceNumber,
                    ProcessStartTime = x.AddTime,
                    ProcessStartTimeStr = x.AddTime != null ? x.AddTime.Value.ToString(DateFormatHelper.DateTimeFormat) : "",
                    ProcessStartUserName = x.AddUserName,
                    OrderStatus = b.ProcessStatusName,
                    OrgName2 = x.Text2,// 选择部门名称
                    OrgName3 = x.Text3,// 组织单元3
                    OrgName4 = x.Text4,// 组织单元4
                    OrgName5 = x.Text5,// 组织单元5
                    OfficerDesc = x.Text6,// 目录1 离职补员/新增招聘
                    //= x.Text7,// 目录2 正式员工/劳务工
                    //= x.Text8,// 目录3 编制内/编制外
                    //= x.Text9,// HC编制数
                    PostName = x.Text10,// 岗位名称
                    PostLevel = x.Text11,// 岗位职级
                    OrgName6 = x.Text16,// 组织单元6
                    OrgName7 = x.Text18,// 组织单元7
                    DemandDesc = x.TextArea1,// 需求描述
                    Suggestions = x.TextArea2,// 人事建议
                    OverTime = b.FinishTime,
                    OverTimeStr = b.FinishTime != null && b.FinishTime != DateTime.MinValue ? b.FinishTime.Value.ToString(DateFormatHelper.DateTimeFormat) : "",
                    Order = a.Order,
                    UserName = t.UserName,
                    CCUserName = c != null ? c.UserName : "",
                    InstanceId = i.InstanceId,
                    Name = a.Name,
                    GrandNodeId = a.GrandNodeId,
                    ActivityId = a.ActivityId,
                });
            var listViewDto = await listQueryable.MergeTable().OrderBy(x => x.ProcessStartTime, OrderByType.Desc).ToListAsync();

            var dataList = new List<ZPSPXTDto>();
            var groupList = listViewDto.GroupBy(x => x.InstanceNumber).ToList();

            groupList.ForEach(x =>
            {
                var item = x.First();

                item.CCUserName = x.Select(q => q.CCUserName).Distinct().JoinAsString(",");

                var activities = x.OrderBy(x => x.Order).ToList()
                   .GroupBy(b => new { b.InstanceId, b.Name, b.GrandNodeId })
                   .ToDictionary(k => k.Key, v => v.ToList());

                var index = 0;
                foreach (var activity in activities)
                {
                    index++;
                    if (activity.Key.Name == "开始")
                    {
                        continue;
                    }
                    if (index == 1)
                    {
                        item.FirstApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 2)
                    {
                        item.SecondApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 3)
                    {
                        item.ThirdApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 4)
                    {
                        item.FouthApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                    if (index == 5)
                    {
                        item.FifthApprover = activity.Value.Select(s => s.UserName).Distinct().JoinAsString(",");
                    }
                }

                dataList.Add(item);
            });

            return dataList;
        }

        public async Task FixData()
        {
            var instances = _db.Queryable<CommonApprovalProcess>().Where(x => x.BTID == "ZPSPXT").ToList();
            foreach (var instance in instances)
            {
                var datas = _dbEngine.Queryable<Instances, InstanceParams>((i, p) => i.InstanceId == p.InstanceId)
                    .Where((i, p) => i.Number == instance.InstanceNumber).Select((i, p) => p).ToList();
                instance.Text15 = datas.FirstOrDefault(x => x.Key == "orgCode6")?.Value ?? "";
                instance.Text16 = datas.FirstOrDefault(x => x.Key == "orgName6")?.Value ?? "";
                instance.Text17 = datas.FirstOrDefault(x => x.Key == "orgCode7")?.Value ?? "";
                instance.Text18 = datas.FirstOrDefault(x => x.Key == "orgName7")?.Value ?? "";
                instance.TextArea2 = datas.FirstOrDefault(x => x.Key == "textarea2")?.Value ?? "";

                _db.Updateable(instance).WhereColumns(x => x.InstanceNumber).ExecuteCommand();

                var ccUsers = new List<InstanceCCUsers>();
                var ccUserParam = datas.FirstOrDefault(x => x.Key == "ccUsers")?.Value;
                if (!string.IsNullOrWhiteSpace(ccUserParam))
                {
                    var jArray = JArray.Parse(ccUserParam);
                    if (jArray != null)
                    {
                        foreach (var data in jArray)
                        {
                            var jObj = (JObject)data;
                            if (jObj.ContainsKey("userId") && jObj.ContainsKey("userName") &&
                                Guid.TryParse(jObj["userId"].ObjToString(), out Guid UserId))
                            {
                                ccUsers.Add(new InstanceCCUsers
                                {
                                    Id = Guid.NewGuid(),
                                    InstanceNumber = instance.InstanceNumber,
                                    UserId = UserId,
                                    UserName = jObj.ContainsKey("userName") ? jObj["userName"].ObjToString() : "",
                                    WorkNumber = jObj.ContainsKey("workNumber") ? jObj["workNumber"].ObjToString() : "",
                                    CreateTime = DateTime.Now,
                                    CCType = 1
                                });
                            }
                        }
                    }
                }
                if (ccUsers.Any())
                {
                    var users = _dbPlatform.Queryable<Users>().Where(x => ccUsers.Select(q => q.UserId).Contains(x.UserId))
                        .Select(x => new { x.UserId, x.WorkNumber }).ToList();
                    ccUsers.ForEach(x =>
                    {
                        x.WorkNumber = users.FirstOrDefault(q => q.UserId == x.UserId)?.WorkNumber ?? "";
                    });
                    _db.Deleteable<InstanceCCUsers>().Where(x => x.InstanceNumber == instance.InstanceNumber && x.CCType == 1).ExecuteCommand();
                    _db.Insertable(ccUsers).ExecuteCommand();
                }
            }
        }
    }
}
